Service的启动过程(二)

继上一篇Service的启动过程(一),本篇将继续对service的另一种启动方式,即绑定service进行分析。

同样的,我们从ContextImpl的bindService开启这个流程的分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//Service的绑定状态,绑定状态下的Service用于和组件进行交互
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
//通过ServiceConnection获取到一个InnterConnection,它实际上是个Binder,
//后面AMS通过这个binder和服务端进行connection的通信
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);//通过ServiceConnection构造一个ServiceDispatcher
} else {
throw new RuntimeException("Not supported in system context");
}
//检验intent,从4.4开始 service的隐式调用将不安全,5.1以后不支持隐式调用
validateServiceIntent(service);
try {
IBinder token = getActivityToken();//取到activity的token,实际上是ActivityRecord的appToken
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess();
//Binder IPC调用,通过AMS来进一步绑定Service 这里调用的是bindService,注意要和startService做区分
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
return false;
}
}

service的bind过程相比启动过程稍微复杂一点,因为bind需要将service绑定到组件上,这个需要通过一个回调来通知客户组件,bindServiceCommon中,首先会获取到一个IServiceConnection,实际上是个InnerConnection,它是个Binder,AMS端通过它来通知客户组件是否建立到Service的连接,随后通过Binder IPC调用bindService进一步的绑定操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//service的绑定过程,这里的caller是个binder,它代表了应用端
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
……
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType,
connection, flags, userId);
}
}

//bind过程的进一步处理
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
//获取调用者的进程信息
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {//未找到的话抛出安全异常
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when binding service " + service);
}

ActivityRecord activity = null;
if (token != null) {
//token不为null时需要找到token对应的ActivityRecord
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
}

int clientLabel = 0;
PendingIntent clientIntent = null;
……
final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
//获取启动的service信息,同启动方式的一样
//其内部会为service创建ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;//取到service对应的ServiceRecord,它实际上是个binder

final long origId = Binder.clearCallingIdentity();

try {
……

AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
//代表一个客户组建的绑定连接
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);

IBinder binder = connection.asBinder();//这个是应用端传来的IServiceConnection binder
//这个connection可以对应多个ConnectionRecord,可见它是可以被多个组件绑定复用的binder
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);//添加到ServiceRecord对应的connections列表中
b.connections.add(c);//添加到AppBindRecord的连接列表中
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);//如果客户组件是Activity 添加到其对应的连接列表中
}
b.client.connections.add(c);//添加到客户端进程的连接列表中
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c);
}
clist = mServiceConnections.get(binder);//AMS的服务记录列表,这个同ServiceRecord的
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);//添加到AMS对应的连接列表中
//设定的标记是BIND_AUTO_CREATE
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//这里会启动service的实例 调用onCreate回调
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
//如果service对应进程不为null,更新其对应的oom_adj和LRU
if (s.app != null) {
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
mAm.updateOomAdjLocked(s.app);
}

//如果service已经运行了,当再有组件进行绑定时就可以立马发布连接状态
//b.intent.received 为true表示service binder实体在AMS端已经被初始化过了
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {}

if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {//表示还未请求绑定过
//否则需要进一步启动service 执行bind的过程
requestServiceBindingLocked(s, b.intent, callerFg, false);
}

getServiceMap(s.userId).ensureNotStartingBackground(s);

} finally {
Binder.restoreCallingIdentity(origId);
}

return 1;
}

AMS端的绑定过程做了以下几件事:

  1. 获取启动的service信息,同时会为要启动的service创建ServiceRecord(如果不存在的话)
  2. 为需要绑定的客户组件创建ConnectionRecord,它代表了一个客户连接。并将其存储在多个连接列表中方便存取。
  3. 通过bringUpServiceLocked启动service实例,这个方法我们之前介绍过.
  4. 通过requestServiceBindingLocked请求执行service的bind过程,这个最终会调用requestServiceBindingLocked通过ApplicationThread来通知应用端绑定service.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//应用端service的绑定流程
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);//取到对应的service实例
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
try {
if (!data.rebind) {
//service的绑定回调 onBind返回的实际上是一个Binder server
IBinder binder = s.onBind(data.intent);
//创建好binder server后然后进行publish 将service发布出去
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {}
}
}

从客户端绑定service的流程来看,它除了会回调service onBind来返回一个IBinder实体,这个IBinder实体它实际上是我们的服务实体,这里它将通过AMS的publishService来发布该服务,按理来说这是service的binder实体第一次穿过Binder驱动,驱动此时会记录下该Binder节点,同时service并不会被SM所知,因此我们的service实际上是作为一个匿名binder存在的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//在service执行完onBind的流程后 会返回一个Binder server,这里对其进行发布
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}

synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}

//进一步发布service,这里的service时作为Binder本地代理端的
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
//发布实际上就是将service通过之前注册的connection回调发送给相应的组件
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
try {
//需要注意,这里的service实际上为binder client端,如果service运行于单独的进程中
//那么这个service返回给应用进程组件后,实际上它在java端是一个BinderProxy,在native端它是一个BpBinder
c.conn.connected(r.name, service);
} catch (Exception e) {}
}
}
}

serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}

通过publishServiceLocked发布的service client binder最终会通过客户组件注册的接口回调给客户端。

坚持原创技术分享,您的支持将鼓励我继续创作!